// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package ssa

// FuseIntegerComparison优化不等式，如“1<=x&&x<5”，
// 可以将其优化为“无符号（x-1）<4”。
// None
// 寻找分支结构，如：
// None
// P
// |\
// |b
// |/ \
// s0 s1
// None
// 在我们的示例中，p的控件“1<=x”，b的控件“x<5”，
// s0和s1是比较的if和else结果。
// None
// 这将优化为：
// None
// P
// \
// B
// / \
// s0 s1
// None
// 其中b具有组合控制值“无符号（x-1）<4”。
// 随后的过程将熔断p和b。
func fuseIntegerComparisons(b *Block) bool {
	if len(b.Preds) != 1 {
		return false
	}
	p := b.Preds[0].Block()
	if b.Kind != BlockIf || p.Kind != BlockIf {
		return false
	}

	// 如果b很可能被忽略，则不要合并控制值。
	if p.Likely == BranchLikely && p.Succs[0].Block() != b {
		return false
	}
	if p.Likely == BranchUnlikely && p.Succs[1].Block() != b {
		return false
	}

	// 检查控制值是否组合成一个整数不等式
	// 以后可以进一步优化。
	bc := b.Controls[0]
	pc := p.Controls[0]
	if !areMergeableInequalities(bc, pc) {
		return false
	}

	// 如果第一个（真）后继者匹配，那么我们有一个析取（| |）。
	// 如果第二个（false）后继者匹配，则我们有一个连词（&&）。
	for i, op := range [2]Op{OpOrB, OpAndB} {
		if p.Succs[i].Block() != b.Succs[i].Block() {
			continue
		}

		// TODO（mundaym）：我们是否也应该检查执行b的成本？
		// 目前，我们可能会推测执行b，即使b包含
		// 很多说明。我们可以检查len（b值）
		// 低于固定数额。但是，请记住
		// 其他优化过程可能会降低b的成本
		// 重要的是，我们不应该过于保守。
		if !canSpeculativelyExecute(b) {
			return false
		}

		// 以逻辑方式组合p和b的控制值。
		v := b.NewValue0(bc.Pos, op, bc.Type)
		v.AddArg(pc)
		v.AddArg(bc)

		// 将组合控制值设置为b的控制值。
		b.SetControl(v)

		// 修改p，使其直接跳到b。
		p.removeEdge(i)
		p.Kind = BlockPlain
		p.Likely = BranchUnknown
		p.ResetControls()

		return true
	}

	// TODO:无法取消条件以合并控件。
	return false
}

// GetContintargindex返回作为索引的第一个参数的索引
// 常量整数或-1（如果不存在此类参数）。
func getConstIntArgIndex(v *Value) int {
	for i, a := range v.Args {
		switch a.Op {
		case OpConst8, OpConst16, OpConst32, OpConst64:
			return i
		}
	}
	return -1
}

// isSignedInequality报告op是否表示不等式<或≤
// 在签名域中。
func isSignedInequality(v *Value) bool {
	switch v.Op {
	case OpLess64, OpLess32, OpLess16, OpLess8,
		OpLeq64, OpLeq32, OpLeq16, OpLeq8:
		return true
	}
	return false
}

// isUnsignedInequality报告op是否表示不等式<或≤
// 在未签名的域中。
func isUnsignedInequality(v *Value) bool {
	switch v.Op {
	case OpLess64U, OpLess32U, OpLess16U, OpLess8U,
		OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
		return true
	}
	return false
}

func areMergeableInequalities(x, y *Value) bool {
	// 我们需要这两个不等式要么在有符号域中，要么在无符号域中。
	// TODO（mundaym）：当我们有一个Eq op时，合并也会很好
	// 可以转换为一个更小的/Leq。例如，在未签名的
	// 域'x==0 | | 3<x'等同于'x<=0 | | 3<x'
	inequalityChecks := [...]func(*Value) bool{
		isSignedInequality,
		isUnsignedInequality,
	}
	for _, f := range inequalityChecks {
		if !f(x) || !f(y) {
			continue
		}

		// 检查这两个不等式是否与常数进行比较。
		xi := getConstIntArgIndex(x)
		if xi < 0 {
			return false
		}
		yi := getConstIntArgIndex(y)
		if yi < 0 {
			return false
		}

		// 检查不等式的非常量参数
		// 都是一样的。
		return x.Args[xi^1] == y.Args[yi^1]
	}
	return false
}
